﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpPickActionBase.h"

// ui Doc & View
#include "IUiDocumentViewManager.h"
#include "IUiDocument.h"
#include "IUiView.h"
#include "UiViewUtils.h"

// ui Frame & Command
#include "ICommandManager.h"
#include "ICommand.h"
#include "ICamera.h"


// Publish版本配置
#include "IPublishConfig.h"

// Pick
#include "IViewerContext.h"
#include "IPickTarget.h"
#include "IPickResult.h"
#include "IPick.h"
#include "IPickEvent.h"
#include "IPickCandidates.h"
#include "IRectPickContext.h"
#include "IPointPickContext.h"
#include "IPickFilter.h"
#include "IPicker.h"
#include "ISelection.h"
#include "IHighlights.h"
#include "IPreHighlights.h"
#include "IApplicationUserOptions.h"


// model
#include "IModelView.h"
#include "IUserTransaction.h"
#include "IGraphicsPlane.h"
#include "IEditMode.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IGraphicsNodeReference.h"
#include "IElementModelShape.h"
#include "IGraphicsElementShape.h"

// ShapeHandle
#include "IElementShapeHandle.h"
#include "ElementLocatorUtils.h"

// Geometry 
#include "AlgorithmIntersect.h"
#include "ILine3d.h"

// Render Temp Line
#include "IPureGraphicsElement.h"
#include "IGraphicsStyle.h"
#include "IGraphicsStyleData.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IGraphicsStyleManager.h"
#include "IGraphicsLine.h"

// 日志记录
#include "JournalUtils.h" 
#include "IJournalCheckData.h"
#include "ICategoryLibrary.h"
#include "ICategory.h"

// gcmp
#include "GbmpUiPlatformCommandIds.h"
#include "ICanvas.h"
#include "IDrawingTableGripPointsConfig.h"
#include "IDrawingTableSelectionService.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;



CREATE_DEBUG_MODE(GBMPDontPrintCandidateOnStatusBar, L"状态栏不显示拾取候选项", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20"
    , L"打开此开关，状态栏将隐藏当前拾取的候选项信息。");

CREATE_DEBUG_MODE(GBMPDisplayElementTriangleNumber, L"显示所选对象的三角面片数量", gcmp::DebugModeGroup::DMGT_VIEW, L"GDMPLab", L"2023-12-20"
    , L"打开此开关，可在选中构件时，在StatusBar中显示该构件的三角面片数量。");

CREATE_DEBUG_MODE(GBMPPickFaceInWireframeMode, L"线框模式下拾取面", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20"
    , L"打开此开关，可在视图线框模式下拾取面。");

EXPOSE_DEBUG_MODE_EXPORT(DisplayMousePositionInReplay, GCMP_UI_VIEW_INTERFACE_EXPORT);
EXPOSE_DEBUG_MODE_EXPORT(GbmpSelectRectSmartColor, GCMP_UI_VIEW_INTERFACE_EXPORT);

CREATE_DEBUG_MODE(GBMPPickSegmentOfPolyCurve, L"多段线分段拾取", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"打开此开关，开启多段线分段拾取功能。");

CREATE_DEBUG_MODE(GBMPActivePickResults, L"框选时动态预高亮框选结果", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20"
    , L"打开此开关，可在框选时动态预高亮框选到的结果。");
CREATE_DEBUG_MODE(PickGNodeRefsFiltered, L"开启点选拾取被过滤掉的GNodeRefs", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"开启点选拾取被过滤掉的GNodeRefs");
CREATE_DEBUG_MODE(GrepSizeThresholdForLargeScene, L"设置用来判断大场景的Grep数量阈值", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"设置用来判断大场景的Grep数量阈值");

CREATE_DEBUG_MODE(CtlrDontNeedTableItemGripPoints, L"Ctrl选择不需要生成单元格夹点", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"Ctrl选择不需要生成单元格夹点");
CREATE_DEBUG_MODE(ShiftUpdateSelectionSelectionForTable, L"Shift按下处理表格选择集更新", gcmp::DebugModeGroup::DMGT_GREP_AND_PICKSNAP, L"GDMPLab", L"2023-12-20", L"Shift按下处理表格选择集更新");
namespace
{
    void LogSelectionInfo(gcmp::IDocument* pDoc)
    {
        std::map<std::wstring, int> allElementCategoryInfo;
        const auto& gnodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
        ICategoryLibrary* pCategoryLib = ICategoryLibrary::Get(pDoc);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pCategoryLib, L"无效指针pCategoryLib",L"GDMPLab",L"2024-03-30");

        for (auto it = gnodeRefs.begin(); it != gnodeRefs.end(); ++it)
        {
            IElement* pElem = pDoc->GetElement((*it)->GetElementId());
            DBG_WARN_AND_CONTINUE_UNLESS(pElem, L"无效指针pElem",L"GDMPLab",L"2024-03-30");
            IElementBasicInformation* pElementBasicInfo = pElem->GetBasicInformation();
            DBG_WARN_AND_CONTINUE_UNLESS(pElementBasicInfo, L"无效指针pElementBasicInfo",L"GDMPLab",L"2024-03-30");
            const UniIdentity& category = pElementBasicInfo->GetCategoryUid();

            const ICategory* pCategory = pCategoryLib->GetCategory(category);
            DBG_WARN_AND_CONTINUE_UNLESS(pCategory, L"无效指针pCategory",L"GDMPLab",L"2024-03-30");
            std::wstring elementCategoryName = pCategory->GetName();
            if (allElementCategoryInfo.find(elementCategoryName) == allElementCategoryInfo.end())
            {
                allElementCategoryInfo[elementCategoryName] = 1;
            }
            else
            {
                allElementCategoryInfo[elementCategoryName]++;
            }
        }

        if (!allElementCategoryInfo.empty())
        {
            std::wostringstream woss;
            for (std::map<std::wstring, int>::const_iterator iter = allElementCategoryInfo.begin(); iter != allElementCategoryInfo.end(); iter++)
            {
                if (iter == allElementCategoryInfo.begin())
                {
                    woss << L"{" + iter->first + L":" + StringUtil::ToWString<int>(iter->second) + L"}";
                }
                else
                {
                    woss << JOURNAL_RESULT_TEXT_SEPARATOR << L"{" + iter->first + L":" + StringUtil::ToWString<int>(iter->second) + L"}";
                }
            }

            OwnerPtr<gcmp::IJournalCheckData> opResultData = IJournalCheckData::Create();
            DBG_WARN_AND_RETURN_VOID_UNLESS(opResultData, L"CREATE_JOURNAL_DATA(IJournalCheckData, JOURNAL_RESULT_DATA)返回空指针",L"GDMPLab",L"2024-03-30");
            opResultData->SetName(L"allSelectionElement");
            opResultData->SetData(woss.str(), gcmp::JournalCheckDataType::Text_LIST);
            JournalUtils::LogOrCompareCheckData(TransferOwnership(opResultData));
        }
    }

    class RemoveAuxiliaryElementHelper
    {
    public:
        RemoveAuxiliaryElementHelper(const IDocument*pDoc) :m_pDoc(pDoc) {}
        bool operator()(const OwnerPtr<IGraphicsNodeReference>& ref) const
        {
            IElement* pElement = m_pDoc->GetElement(ref->GetElementId());
            IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);

            return (pShapeHandle != nullptr);
        }

    private:
        const IDocument* m_pDoc;
    };
}

void GbmpPickActionUtil::UpdateCandidatesSingleton(IUiView* pCurrentView,
                                                int screenX, 
                                                int screenY, 
                                                const Vector3d& pos,
                                                const gcmp::IPickEvent* pPickPostProcesserEvent,
                                                const IPickFilter* pPickFilter, 
                                                const gcmp::IPickTarget* pPickTarget,
                                                bool isPickingHighlightOnlyGraphicsNodeAllowed,
                                                bool selectByFaceInteriorEnabled/* = true*/,
    int pickTolerance,
    bool isHoveringHighlight)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"pCurrentView is nullptr!",L"GDMPLab",L"2024-03-30");
    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc is nullptr!",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"Document为空",L"GDMPLab",L"2024-03-30");

    if (JournalUtils::IsInReplay()) {
        JournalUtils::SetMousePoint(pos);
    }
    std::vector<const IGraphicsElementShape*> apiGreps = pCurrentView->GetEditableGreps();
    double tolerance;
    if (pickTolerance < 0)
        tolerance = UiViewUtility::GetPickTolerance(pCurrentView);
    else
        tolerance = UiViewUtility::ComputeWorldWidthFromPixel(pCurrentView, pickTolerance);

    //把在屏幕上取的点转换成射线
    Vector3d startPt = UiViewUtility::ScreenPositionToWorldPosition(pCurrentView, screenX, screenY, 0);
    Vector3d endPt = UiViewUtility::ScreenPositionToWorldPosition(pCurrentView, screenX, screenY, 1);
    auto ray = ILine3d::Create(startPt, endPt);

    OwnerPtr<IPointPickContext> pickContext = gcmp::IPointPickContext::Create();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pickContext, L"pickContext is nullptr!",L"GDMPLab",L"2024-03-30");

    pickContext->SetDocument(pDoc);
    pickContext->SetViewerContext(pCurrentView->GetViewerContext()->Clone());
    pickContext->SetGraphicsElementShapes(apiGreps);
    pickContext->SetRay(ray.get());
    pickContext->SetPickTolerance(tolerance);

    // 接口测试覆盖
    const double MAX_TOLERANCE_IN_LARGE_SCENE = 100.0;
    pickContext->SetPickToleranceForLargeScene(MAX_TOLERANCE_IN_LARGE_SCENE);

    pickContext->SetAllowPickingHighlightOnlyGraphicsNode(isPickingHighlightOnlyGraphicsNodeAllowed);

    //暂时保留，如果UI层全部替换为API事件形式以后，可以删除
    if(pPickFilter != nullptr)
        pickContext->SetPickFilter(pPickFilter);

    if (pPickPostProcesserEvent)
    {
        pickContext->SetPickPostProcessEvent(pPickPostProcesserEvent);
    }
    pickContext->SetMousePosition(pos);
    const IModelView* pModelView = pCurrentView->GetModelView();
    if (pModelView && pModelView->GetDisplayMode() == ModelViewDisplayMode::Wireframe)
    {
        pickContext->SetSelectByFaceInteriorEnabled(false);
    }
    else
        pickContext->SetSelectByFaceInteriorEnabled(selectByFaceInteriorEnabled);

    if (DEBUG_MODE(GBMPPickFaceInWireframeMode))
    {
        pickContext->SetSelectByFaceInteriorEnabled(true);
    }

    if(pPickTarget)
    {
        //pickContext->SetPickTarget(pPickTarget->Clone());
        OwnerPtr<IPickTarget> opTarget = pPickTarget->Clone();
        if (opTarget)
        {
            if (DEBUG_MODE(GBMPPickSegmentOfPolyCurve))
            {
                opTarget->EnableCurve();
                opTarget->EnableSegmentOfPolyCurve();
            }
            else
                opTarget->DisableSegmentOfPolyCurve();
        }
        pickContext->SetPickTarget(TransferOwnership(opTarget));
    }

    if (DEBUG_MODE(PickGNodeRefsFiltered))
        pickContext->SetCollectPickResultsFiltered(true);

    if (DEBUG_MODE(GrepSizeThresholdForLargeScene))
        pickContext->SetGrepSizeThresholdForLargeScene(1000);

    OwnerPtr<IPickResult> pickResult = gcmp::IPicker::PickByPoint(pickContext.get());
    if (!pickResult) 
        return;

    DBG_WARN_AND_RETURN_VOID_UNLESS(IPickCandidates::Get() && IPreHighlights::Get(), L"singleton instance is nullptr!",L"GDMPLab",L"2024-03-30");

    IPickCandidates::Get()->Clear();

    IPreHighlights::Get()->Clear();

    FOR_EACH(itIPick, pickResult->GetAllPicks())
    {
        IPickCandidates::Get()->AddPick(TransferOwnership(itIPick));
    }
    IPickCandidates::Get()->SetDefaultCurrentPickIndex(pDoc);


    //掠过高亮开关关闭时，直接返回
    if (isHoveringHighlight == false)
        return;

    if (IPickCandidates::Get()->GetCount() > 0)
    {
        if (DEBUG_MODE(PickGNodeRefsFiltered))
        {
            std::vector<OwnerPtr<IGraphicsNodeReference>> gNodeRefs;
            if (!pickResult->GetAllGraphicsNodeReferencesFiltered().empty() && pickResult->GetAllGraphicsNodeReferencesFiltered().at(0))
                gNodeRefs.emplace_back(pickResult->GetAllGraphicsNodeReferencesFiltered().at(0)->Clone());
            // 对于点选，一个pick对应一个GNodeRef，因此直接拿最接近屏幕的 index为0 的结果用于显示
            IPreHighlights::Get()->AddGraphicsNodeReferences(gNodeRefs);
        }
        else
        {
            if (IPickCandidates::Get()->GetCurrentPick())
                IPreHighlights::Get()->AddGraphicsNodeReferences(IPickCandidates::Get()->GetCurrentPick()->GetAllGraphicsNodeReferences());
        }
    }
}


GbmpPickActionBase::GbmpPickActionBase():
m_upUserTransaction(nullptr),
m_auxElementId(-1),
m_isMoveAllowed(true),
m_bSelectByFaceInteriorEnabled(true),
m_isPickingHighlightOnlyGraphicsNodeAllowed(false),
m_pickPixelTolerance(-1),
m_isHoveringHighlight(true),
m_pDebugDrawElement(nullptr)
{
    m_status = PS_GBMP_NOTSTART;
    m_pickTarget = IPickTarget::Create();
    m_opPickPostProcessEvent = IPickEvent::Create(L"PickPostProcess", nullptr);
    m_opRectPickPostProcessEvent = IPickEvent::Create(L"RectPickPostProcess", nullptr);
}


GbmpPickActionBase::~GbmpPickActionBase()
{
    if (m_pDebugDrawElement)
    {
        IDocument *pDoc = m_pDebugDrawElement->GetDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
        pDoc->DeleteElement(m_pDebugDrawElement->GetElementId());
    }

    if (m_rectangleSelectID.IsValid())
    {
        IDocument* pDoc = GetDoc();
        if (pDoc)
        {
            bool isSucceed = pDoc->DeleteElement(m_rectangleSelectID);
            if (isSucceed)
            {
                m_rectangleSelectID = ElementId::InvalidID;
            }
        }
        else
        {
            DBG_WARN(L"若没有pDoc，则m_rectangleSelectID对应的Element创建不出来，所以不用处理。",L"GDMPLab",L"2024-03-30");
        }
    }
}
void GbmpPickActionBase::InitAction(gcmp::IUiView* pCurrentView)
{
    IPickCandidates::Get()->Clear();
    IPreHighlights::Get()->Clear();
    ICanvas *pCanvas = pCurrentView->GetCanvas();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
    pCanvas->Refresh();

    if (IApplicationUserOptions* pUserOption = IApplicationUserOptions::Get())
    {
        m_isHoveringHighlight = pUserOption->IsHoverHighlightEnabled();
}
}
bool GbmpPickActionBase::OnKeyDown(IUiView* pCurrentView, int nChar )
{
    IPickCandidates* candidates = IPickCandidates::Get();
    // tab
    if (nChar == 9 && candidates->GetCount() > 0)
    {
        int index = candidates->GetCurrentPickIndex();
        if (IsKeyAndButtonPressed(VK_SHIFT))
        {
            index = (index == 0) ? (int)candidates->GetCount()-1 : index-1;
        }
        else
        {
            index = (index + 1) % candidates->GetCount();
        }
        candidates->SetCurrentPickIndex(index);
        IPreHighlights::Get()->SetGraphicsNodeReferences(candidates->GetCurrentPick()->GetAllGraphicsNodeReferences());
        UpdateView();
    }
    else if (nChar == VK_ESCAPE || 
        (IsReturnKeyNeedCanceled() && (nChar == VK_RETURN || nChar == VK_SPACE)))
    {
        if (m_upUserTransaction!=nullptr && m_upUserTransaction->IsStarted())
        {
            m_upUserTransaction->Rollback();
        }

        ClearSelection(pCurrentView->GetUiDocument()->GetDbDocument());

        OnSelectionChanged();
        UpdateView();
    }
    else if (nChar == VK_DELETE)
    {
        std::wstring cmdName = ID_CMD_GBMP_DELETE_SELECTION;
        const ICommand* cmdNameCorrespondCmdItem = ICommandManager::Get()->GetCommand(cmdName);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(cmdNameCorrespondCmdItem, cmdName + L"对应的命令为空。",L"GDMPLab",L"2024-03-30");
        if (cmdNameCorrespondCmdItem->IsVisible() && cmdNameCorrespondCmdItem->IsEnabled())
        {
            ICommandManager::Get()->SendCommand(cmdName); 
        }
    }
    return ActionBase::OnKeyDown(pCurrentView,nChar);
}


void GbmpPickActionBase::OnSelectionChanged()
{
    LogSelectionInfo(GetDoc());
}

bool GbmpPickActionBase::IsAuxiliaryElement(const IDocument *pDoc,const ElementId& id)
{
    IElement* pElement = pDoc->GetElement(id);
    IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);
    IElementBasicInformation* pBasicInfo = nullptr;
    if (pElement)
    {
        pBasicInfo = pElement->GetBasicInformation();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInfo, L"pBasicInfo指针无效",L"GDMPLab",L"2024-03-30");
    }
    return (pShapeHandle != nullptr) || ElementLocatorUtils::IsElementLocatorMovementHandler(pDoc, id) 
        || ElementLocatorUtils::IsElementLocatorRotationHandler(pDoc, id) || ElementLocatorUtils::IsElementLocatorPlanarMoveHandler(pDoc, id)
        || (pShapeHandle == nullptr && pBasicInfo->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_AUXILIARY_ELEMENT);
}

bool GbmpPickActionBase::OnLButtonDown(IUiView* pCurrentView, const Vector3d& pos)
{
    m_auxElementId = ElementId::InvalidID;
    m_status = PS_GBMP_LBUTTON_DOWN;
    m_worldStart = pos;
    IDocument *pDoc = pCurrentView->GetUiDocument()->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, true, L"Document指针无效",L"GDMPLab",L"2024-03-30");

    //case 1: 没有任何对象，并且Ctrl和Shift都没按下
    bool clear = !IsKeyAndButtonPressed(VK_CONTROL) && !IsKeyAndButtonPressed(VK_SHIFT) && !IsDraggingAwaySelectedElementsEnabled(pCurrentView);
    if (IPickCandidates::Get()->GetCount()==0 && clear)
    {
        ClearSelection(pDoc);
        OnSelectionChanged();
        UpdateView();

        return false;
    }
    //IHighlights::Get()->Clear();
    //计算与工作平面的交点，并返回所获得的点
    Vector3d posOnWP;
    if (ActionBase::ProjectPositionOnWorkPlane(pCurrentView, pos, posOnWP))
    {
        m_startPt = posOnWP;
    }

    //case 2: 辅助对象的处理要独立于选择集
    if(IPickCandidates::Get()->GetCount() <= 0)
    {
        ICanvas *pCanvas = pCurrentView->GetCanvas();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
        pCanvas->Refresh();
        //如果没有选择的对象直接返回
        return false;
    }

    const GraphicsNodeReferenceOwnerPtrVector& pickCandidate = IPickCandidates::Get()->GetCurrentPick()->GetAllGraphicsNodeReferences();
    if (1 == pickCandidate.size() && IsAuxiliaryElement(pDoc, pickCandidate.at(0)->GetElementId()))
    {
        //辅助对象可以选，但是在通用的选择类中并不合法
        m_auxElementId = pickCandidate.at(0)->GetElementId();
        if (clear)
        {
            IPickCandidates::Get()->Clear();
            IPreHighlights::Get()->Clear();
        }
        ICanvas *pCanvas = pCurrentView->GetCanvas();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
        pCanvas->Refresh();
        return false;
    }

    //case 3: 一般对象
    if (1 == pickCandidate.size())
    {
        AddToSelection(pDoc, *pickCandidate.at(0), pCurrentView);
    }
    else if (pickCandidate.size() > 1)
    {
        GraphicsNodeReferenceOwnerPtrSet pickCandidateSet = OwnerPtrContainerUtil::TransformVectorToSet(pickCandidate);
        AddToSelectionGroup(pDoc, pickCandidateSet);
    }
    OnSelectionChanged();
    UpdateView();

    return true;
}

void GbmpPickActionBase::HasTableInSelection(IDocument* pDoc, const GraphicsNodeReferenceOwnerPtrSet& selections, bool& hasTable) const
{
    FOR_EACH(sele, selections)
    {
        if (hasTable)
        {
            break;
        }
        if (!sele)
        {
            continue;
        }
        ElementId id = sele->GetElementId();
        IElement* pElement = pDoc->GetElement(id);
        if (!pElement)
        {
            continue;
        }
        IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
        if (!pBasicInformation)
        {
            continue;
        }
        if (pBasicInformation->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT)
        {
            hasTable = true;
            break;
        }
    }
}

void GbmpPickActionBase::AddToSelection(IDocument* pDocument, const IGraphicsNodeReference& pickResult, const IUiView* pCurrentView)
{
    IDocument* pDoc = pDocument;

    //需要确认改进：
    //(1) 不能被选择的为什么还能被加进来（最好进行更早的过滤，比如在捕捉拾取的时候就传入Filter）
    //(2) 选择集在没有真正被改变时，不需要调用UpdateHighlightOnlySelection/OnSelectionChanged
    //(3）选择集Selection的API需要改进为返回bool值，调用处再利用返回值来判断是否真正影响到选择集合
    //改进完成后这里添加：DBG_WARN_AND_RETURN_VOID_UNLESS(IsCanBeSelect(pDoc, pickResult), L"拾取结果不对", L"GDMPLab", L"2023-12-20");
    //下面这段代码将来要删除，现在是保持原来的逻辑否则要改一些脚本
    if (!IsCanBeSelect(pDoc, pickResult))
    {
        if (IsKeyAndButtonPressed(VK_CONTROL) && !IsKeyAndButtonPressed(VK_SHIFT))
        {
            return;
        }

        if (!IsKeyAndButtonPressed(VK_CONTROL) && !IsKeyAndButtonPressed(VK_SHIFT))
        {
            ISelection::Get()->Clear(pDoc);
            IHighlights::Get()->Clear();
            return;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    //经讨论目前确认为如下行为： 
    //1. Ctrl 总是加 
    //2. Shift总是减 
    //3. 不按ctrl和shift总是替换
    //4. Ctrl+Shift总是求反 
    //////////////////////////////////////////////////////////////////////////
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    bool ctrlKeyPressed = IsKeyAndButtonPressed(VK_CONTROL);
    bool shiftKeyPressed = IsKeyAndButtonPressed(VK_SHIFT);
    ISelection* pGlobalSelection = ISelection::Get();

    // 如果选择集中有表格则总是替换
    bool hasTalbe = false;
    std::vector<IElement*> pElements = pDoc->GetElementsByCategory(BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT);
    if (!pElements.empty())
    {
        const GraphicsNodeReferenceOwnerPtrSet& selections = pGlobalSelection->GetGraphicsNodeReferences();
        HasTableInSelection(pDoc, selections, hasTalbe);
        if (!hasTalbe)
        {
            ElementId id = pickResult.GetElementId();
            IElement* pElement = pDoc->GetElement(id);
            if (pElement)
            {
                IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
                if (pBasicInformation)
                {
                    if (pBasicInformation->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT)
                    {
                        hasTalbe = true;
                    }
                }

            }

        }
    }

    bool isTableShift = false;
    if (DEBUG_MODE(ShiftUpdateSelectionSelectionForTable))
    {
        isTableShift = true;
    }
    
    //1. Ctrl 总是加 
    if (ctrlKeyPressed && !shiftKeyPressed && !hasTalbe)
    {
        pGlobalSelection->AddGraphicsNodeReference(pDoc, pickResult);
    }

    //2. Shift总是减
    if (!ctrlKeyPressed && shiftKeyPressed)
    {
        if (hasTalbe && isTableShift)
        {
            GraphicsNodeReferenceOwnerPtrSet currentPickResults;
            currentPickResults.emplace(pickResult.Clone());
            // 对选择集中所有表格对象重新整理替换；提供辅助接口方便用户调用。
            IDrawingTableSelectionService::ContinuousUpdateSelection(pDoc, currentPickResults);
        }
        else
            pGlobalSelection->DeleteGraphicsNodeReference(pDoc, pickResult);
    }

    GraphicsNodeReferenceOwnerPtrSet nodeRefs;
    nodeRefs.insert(TransferOwnership(pickResult.Clone()));
    //3. 不按ctrl和shift总是替换
    if ((!ctrlKeyPressed && !shiftKeyPressed && !IsDraggingAwaySelectedElementsEnabled(pCurrentView)) || (hasTalbe && !isTableShift))
    {
        pGlobalSelection->ReplaceGroupGraphicsNodeReference(pDoc, nodeRefs);
    }

    //4. Ctrl+Shift总是求反 
    if (ctrlKeyPressed && shiftKeyPressed && !hasTalbe)
    {
        pGlobalSelection->RevertGroupGraphicsNodeReference(pDoc, nodeRefs);
    }
    UpdateHighlightOnlySelection();
}

void GbmpPickActionBase::AddToSelectionGroup(IDocument* pDoc, GraphicsNodeReferenceOwnerPtrSet& pickResults)
{
    //需要确认：
    //根据AddToSelection逻辑推断，不能被选择的对象同样可能被加进来(要一起考虑)
    //参考AddToSelection头部注释

    
    //////////////////////////////////////////////////////////////////////////
    //经讨论目前确认为如下行为： 
    //1. Ctrl 总是加 
    //2. Shift总是减 
    //3. 不按ctrl和shift总是替换
    //4. Ctrl+Shift总是求反
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    bool ctrlKeyPressed = IsKeyAndButtonPressed(VK_CONTROL);
    bool shiftKeyPressed = IsKeyAndButtonPressed(VK_SHIFT);
    ISelection* pGlobalSelection = ISelection::Get();


    // 如果选择集中有表格则总是替换
    bool hasTalbe = false;

    std::vector<IElement*> pElements = pDoc->GetElementsByCategory(BuiltInCategoryUniIdentities::BICU_DRAWING_TABLE_ELEMENT);
    if (!pElements.empty())
    {
        const GraphicsNodeReferenceOwnerPtrSet& selections = pGlobalSelection->GetGraphicsNodeReferences();
        HasTableInSelection(pDoc, selections, hasTalbe);
        if (!hasTalbe)
        {
            HasTableInSelection(pDoc, pickResults, hasTalbe);
        }
    }
    bool isTableCtrl = hasTalbe;
    if (DEBUG_MODE(CtlrDontNeedTableItemGripPoints))
    {
        isTableCtrl = false;
    }
    bool isTableShift = false;
    if (DEBUG_MODE(ShiftUpdateSelectionSelectionForTable))
    {
        isTableShift = true;
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(IDrawingTableGripPointsConfig::Get(), L"IDrawingTableGripPointsConfig::Get()为空",L"GDMPLab",L"2024-03-30");
    
    //1. Ctrl 总是加 
    if (ctrlKeyPressed && !shiftKeyPressed && !isTableCtrl)
    {
        if (DEBUG_MODE(CtlrDontNeedTableItemGripPoints))
        {
            IDrawingTableGripPointsConfig::Get()->SetIsNeedDrawingTableItemGripPoints(false);
            hasTalbe = isTableCtrl;
        }
        pGlobalSelection->AddGroupGraphicsNodeReference(pDoc, pickResults);
        if (DEBUG_MODE(CtlrDontNeedTableItemGripPoints))
        {
            // 对选择集中所有表格对象重新整理替换；提供辅助接口方便用户调用。
            // 如果整个选择集中的内容跨表格或者跨分页了，则所有表格对象被选择
            IDrawingTableSelectionService::DiscreteUpdateSelection(pDoc);
        }
    }

    //2. Shift总是减
    if (!ctrlKeyPressed && shiftKeyPressed && (!hasTalbe || (hasTalbe && isTableShift)))
    {
        if (hasTalbe && isTableShift)
        {
            // 对选择集中所有表格对象重新整理替换；提供辅助接口方便用户调用。
            IDrawingTableSelectionService::ContinuousUpdateSelection(pDoc,pickResults);
        }
        else
            pGlobalSelection->DeleteGroupGraphicsNodeReference(pDoc, pickResults);
    }

    //3. 不按ctrl和shift总是替换
    if ((!ctrlKeyPressed && !shiftKeyPressed) || (hasTalbe && !isTableShift))
    {
        IDrawingTableGripPointsConfig::Get()->SetIsNeedDrawingTableItemGripPoints(true);
        pGlobalSelection->ReplaceGroupGraphicsNodeReference(pDoc, pickResults);
    }

    //4. Ctrl+Shift总是求反
    if (ctrlKeyPressed && shiftKeyPressed && !hasTalbe)
    {
        pGlobalSelection->RevertGroupGraphicsNodeReference(pDoc, pickResults);
    }
    UpdateHighlightOnlySelection();
}

void GbmpPickActionBase::UpdateHighlightOnlySelection()
{
    const std::set<OwnerPtr<IGraphicsNodeReference>, OwnerPtrContainerUtil::LessPredicate<IGraphicsNodeReference>>& selectionGNodeRefs = ISelection::Get()->GetGraphicsNodeReferences();
    std::vector<OwnerPtr<IGraphicsNodeReference>> highLightGNodeRefs;

    OwnerPtrContainerUtil::AddItems(highLightGNodeRefs, selectionGNodeRefs);
    IHighlights::Get()->Clear();
    IHighlights::Get()->AddGraphicsNodeReferences(highLightGNodeRefs);
    if (ISelection::Get()->GetCount() == 1)
    {
        //IHighlights::Get()->AddGraphicsNodeReferences(GetElementAssociatedSelectionObjects(ISelection::Get()->GetGraphicsNodeReferences().begin()->get()->GetElementId()));
    }
}

OwnerPtr<IGraphicsElementShape> GbmpPickActionBase::CreatSelectRectangleGrep(const IUiView* pCurrentView, const gcmp::Vector3d& pos) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCurrentView, L"pCurrentView为空",L"GDMPLab",L"2024-03-30");
    IModelView* pModelView = pCurrentView->GetModelView();

    const ICanvas *pCanvas = pCurrentView->GetCanvas();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
    const ICamera* pCamera = pCanvas->GetCamera();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCamera, L"pCamera为空",L"GDMPLab",L"2024-03-30");

    Vector3d viewDir = pCamera->GetDirection();
    Vector3d upDir = pCamera->GetUpDirection();
    Vector3d uDir = viewDir.Cross(upDir);
    uDir.Normalize();

    Vector2d screenStart, screenPos;
    WorldToScreen(pCurrentView, m_worldStart, screenStart);
    WorldToScreen(pCurrentView, pos, screenPos);
    Vector3d newStart = UiViewUtility::ScreenPositionToWorldPosition(pCurrentView, (int)screenStart.X(), (int)screenStart.Y(), 0.1f);
    Vector3d newEnd = UiViewUtility::ScreenPositionToWorldPosition(pCurrentView, (int)screenPos.X(), (int)screenPos.Y(), 0.1f);
    Vector3d corner[4];
    Vector3d v = newEnd - newStart;
    corner[0] = newStart;
    corner[1] = newStart + uDir * (uDir.Dot(v));
    corner[2] = newEnd;
    corner[3] = newStart + upDir * (upDir.Dot(v));
    gcmp::OwnerPtr<IGraphicsElementShape> opResultGrep(gcmp::IGraphicsElementShape::Create(GraphicsRenderLayer::TransientObjectInTop));
    for (int index = 0; index < 4; ++index)
    {
        int temp = (index == 3) ? -1 : index;
        OwnerPtr<IGraphicsCurve3d> upGCurve = IGraphicsLine::Create(corner[index], corner[temp + 1]);
        opResultGrep->AddChild(TransferOwnership(upGCurve));
    }

    //反选则选择框用虚线绘制
    bool isReversePick = screenStart.X() > screenPos.X() ? true : false;
    if (isReversePick)
    {
        OwnerPtr<IGraphicsStyleData> styleData = IGraphicsStyleData::Create();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(styleData, L"styleData为空",L"GDMPLab",L"2024-03-30");
        styleData->SetProjectionLineStipple(1, 0xff00);
        if (DEBUG_MODE(GbmpSelectRectSmartColor) || ISelection::Get()->GetSelectRectSmartColor())
            styleData->SetProjectionLineSmartColorMode(SmartColorMode::SmartAntiBackgroundColor);
        IGraphicsStyle* pStyleElem = IGraphicsStyle::Create(GetDoc(), ElementCreationOptions::Transient);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStyleElem, L"pStyleElem为空",L"GDMPLab",L"2024-03-30");
        pStyleElem->SetGraphicsStyleData(*styleData);
        opResultGrep->SetGraphicsStyleId(pStyleElem->GetElementId());
    }

    return (TransferOwnership(opResultGrep));
}

void GbmpPickActionBase::DrawSelectRectangle(IUiView* pCurrentView, const gcmp::Vector3d& pos,bool isIntersect)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView, L"不应该传入空的UiView",L"GDMPLab",L"2024-03-30");

    IDocument *pDoc = GetDoc();
    if (!pDoc)
    {
        return;
    }

    IPureGraphicsElement* pElement = nullptr;

    if(!m_rectangleSelectID.IsValid())
    {
        pElement = IPureGraphicsElement::Create(pDoc, ElementCreationOptions::Transient);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"PureGraphicsElement创建失败",L"GDMPLab",L"2024-03-30");
    }
    else
    {
        pElement = quick_cast<IPureGraphicsElement>(pDoc->GetElement(m_rectangleSelectID));
        /*
        当PureGraphicsElement的modelViewId有效时，PureGraphicsElement强依赖于该modelView。
        有可能上次设置的modelView删除了，此时PureGraphicsElement会被删除。
        当切换到其他视图后，此时该action还没析构，m_rectangleSelectID依旧有效，那么通过m_rectangleSelectID有可能拿到nullptr。
        因此这时需要判断下，若为nullptr则重新创建个PureGraphicsElement对象。
        */
        if (!pElement)
        {
            pElement = IPureGraphicsElement::Create(pDoc, ElementCreationOptions::Transient);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"PureGraphicsElement创建失败",L"GDMPLab",L"2024-03-30");
        }
    }

    IElementBasicInformation* pBasicInfo = pElement->GetBasicInformation();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pBasicInfo, L"IPureGraphicsElement::GetBasicInformation()为空",L"GDMPLab",L"2024-03-30");
    pBasicInfo->SetName(L"SelectRectangle");   // 给框选框节点设个特殊的名称
    m_rectangleSelectID = pElement->GetElementId();
    pElement->SetModelViewId(pCurrentView->GetModelViewId());

    OwnerPtr<IGraphicsElementShape> opSelectRectangleGrep = CreatSelectRectangleGrep(pCurrentView, pos);
    if (!opSelectRectangleGrep)
    {
        return;
    }
    opSelectRectangleGrep->SetIsSnappable(false);
    opSelectRectangleGrep->SetIsSelectable(false);
    opSelectRectangleGrep->SetIsClippable(false);

    IElementModelShape* pGraphicsElementShapeBehavior = pElement->GetElementModelShape();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGraphicsElementShapeBehavior, L"pGraphicsElementShapeBehavior为空",L"GDMPLab",L"2024-03-30");
    pGraphicsElementShapeBehavior->SetGraphicsElementShape(TransferOwnership(opSelectRectangleGrep));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement->GetElementModelShape() &&pElement->GetElementModelShape()->GetGraphicsElementShape() &&pElement->GetElementModelShape()->GetGraphicsElementShape()->IsElementTransient(),L"GgpRenderMgr::DrawTmpGrep() 中，IGraphicsElementShape::IsElementTransient() 必须返回 true",L"GDMPLab",L"2024-03-30");
    UpdateView();
}

void GbmpPickActionBase::DrawSelectRectangleInReplay( gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos ,bool isIntersect)
{
    IDocument *pDoc = GetDoc();
    if (!pDoc)
    {
        return;
    }

    OwnerPtr<IGraphicsStyleData> opGraphicsStyleData = IGraphicsStyleData::Create();
    DBG_WARN_AND_RETURN_VOID_UNLESS(opGraphicsStyleData, L"IGraphicsStyleData::Create() 返回空指针？",L"GDMPLab",L"2024-03-30");
    
    OwnerPtr<IGraphicsElementShape> opSelectRectangleGrep = CreatSelectRectangleGrep(pCurrentView,pos);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opSelectRectangleGrep, L"CreatSelectRectangleGrep(pCurrentView,pos) 返回空指针",L"GDMPLab",L"2024-03-30");

    opSelectRectangleGrep->SetIsSnappable(false);
    opSelectRectangleGrep->SetIsSelectable(false);

    std::vector<IGraphicsStyle*> allGraphicsStyle = IGraphicsStyle::GetAllGraphicsStyles(pDoc);
    // L"StyleElemsIntersectSelectRectangleInReplay"
    std::vector<IGraphicsStyle*> pStyleElemsIntersect;
    {
        for (size_t i = 0; i < allGraphicsStyle.size(); ++i)
        {
            IElementBasicInformation* pBaseInfo = allGraphicsStyle[i]->GetBasicInformation();
            if (pBaseInfo && pBaseInfo->GetName() == L"StyleElemsIntersectSelectRectangleInReplay")
            {
                pStyleElemsIntersect.push_back(allGraphicsStyle[i]);
            }
        }
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleElemsIntersect.size() <= 1, L"样式名称重复",L"GDMPLab",L"2024-03-30");
    }
     
    IGraphicsStyle* pStyleElemIntersect;
    if((int)pStyleElemsIntersect.size() == 0)
    {        
        pStyleElemIntersect = IGraphicsStyle::Create(pDoc, ElementCreationOptions::Transient);        
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleElemIntersect != nullptr, L"IGraphicsStyle::Create() 返回空指针",L"GDMPLab",L"2024-03-30");
        pStyleElemIntersect->GetBasicInformation()->SetName(L"StyleElemsIntersectSelectRectangleInReplay");
        pStyleElemIntersect->SetGraphicsStyleData(opGraphicsStyleData->Reset().SetColor(Color(0xff, 0, 0)).SetSectionFaceColor(Color(0xff, 0, 0)));
    }
    else
    {
        pStyleElemIntersect = pStyleElemsIntersect[0];
    }

    // L"StyleElemsNoIntersectSelectRectangleInReplay"
    std::vector<IGraphicsStyle*> pStyleElemsNoIntersect;
    {
        for (size_t i = 0; i < allGraphicsStyle.size(); ++i)
        {
            IElementBasicInformation* pBaseInfo = allGraphicsStyle[i]->GetBasicInformation();
            if (pBaseInfo && pBaseInfo->GetName() == L"StyleElemsNoIntersectSelectRectangleInReplay")
            {
                pStyleElemsNoIntersect.push_back(allGraphicsStyle[i]);
            }
        }
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleElemsNoIntersect.size() <= 1, L"样式名称重复",L"GDMPLab",L"2024-03-30");
    }

    IGraphicsStyle* pStyleElemNoIntersect;
    if((int)pStyleElemsNoIntersect.size() == 0)
    {
        pStyleElemNoIntersect = IGraphicsStyle::Create(pDoc, ElementCreationOptions::Transient);        
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleElemNoIntersect != nullptr, L"IGraphicsStyle::Create() 返回空指针",L"GDMPLab",L"2024-03-30");
        pStyleElemNoIntersect->GetBasicInformation()->SetName(L"StyleElemsNoIntersectSelectRectangleInReplay");
        pStyleElemNoIntersect->SetGraphicsStyleData(opGraphicsStyleData->Reset().SetColor(Color(0, 0, 0xff)).SetSectionFaceColor(Color(0, 0, 0xff)));
    }
    else
    {
        pStyleElemNoIntersect = pStyleElemsNoIntersect[0];
    }

    if(!isIntersect)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleElemIntersect != nullptr, L"pStyleElemIntersect为空指针",L"GDMPLab",L"2024-03-30");
        opSelectRectangleGrep->SetGraphicsStyleId(pStyleElemIntersect->GetElementId());
    }
    else
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleElemNoIntersect != nullptr, L"pStyleElemNoIntersect为空指针",L"GDMPLab",L"2024-03-30");
        opSelectRectangleGrep->SetGraphicsStyleId(pStyleElemNoIntersect->GetElementId());
    }
    
    // 绘制
    {
        if (m_pDebugDrawElement)
        {
            IDocument *pDoc = m_pDebugDrawElement->GetDocument();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
            pDoc->DeleteElement(m_pDebugDrawElement->GetElementId());
        }

        m_pDebugDrawElement = IPureGraphicsElement::Create(pDoc, ElementCreationOptions::Transient);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pDebugDrawElement, L"IPureGraphicsElement::Create 返回空指针",L"GDMPLab",L"2024-03-30");
        IPureGraphicsElement* pPureGraphicsElement = quick_cast<IPureGraphicsElement>(m_pDebugDrawElement);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pPureGraphicsElement, L"pPureGraphicsElement为空",L"GDMPLab",L"2024-03-30");
        pPureGraphicsElement->SetModelViewId(pCurrentView->GetModelViewId());
        m_pDebugDrawElement->GetBasicInformation()->SetCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE);
        m_pDebugDrawElement->GetElementModelShape()->SetGraphicsElementShape(TransferOwnership(opSelectRectangleGrep));
    }

    UpdateView();
}

bool GbmpPickActionBase::OnLButtonDoubleClick(IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    m_status = PS_GBMP_LBUTTON_DBCLK;
    return true;
}


bool GbmpPickActionBase::OnMovePoint(IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    ActionBase::OnMovePoint(pCurrentView, pos);

    bool isUpdatedView = false;
    // 如果没有选择到对象则为框选
    if (m_status & PS_GBMP_LBUTTON_DOWN)
    {
        // 如果已经选中物体且未按住ctrl或shift键，则不允许框选
        if ((!IsSelectionEmpty() &&
            !IsKeyAndButtonPressed(VK_CONTROL) &&
            !IsKeyAndButtonPressed(VK_SHIFT)) ||
            (IsDraggingAwaySelectedElementsEnabled(pCurrentView)))
        {
            return true;
        }
        Vector2d screenStart, screenPos;
        WorldToScreen(pCurrentView, m_worldStart, screenStart);
        WorldToScreen(pCurrentView, pos, screenPos);
        // 绘制框选临时绘制对象
        if ((screenPos - screenStart).Length() > gcmp::Constants::LENGTH_EPS)
        {
            DrawSelectRectangle(pCurrentView, pos, screenStart.X() < screenPos.X());
            if(DEBUG_MODE(GBMPActivePickResults))
            {
                bool isReversePick = false;
                OwnerPtr<IPickResult> pickResults = GetPickResults(pCurrentView, pos, isReversePick);
                if (pickResults)
                {
                    if (!pickResults->IsEmpty())
                    {
                        DBG_WARN_AND_RETURN_UNLESS(pickResults->GetSize() == 1, false, L"框选选择集只可能是一个PickCandidate结果",L"GDMPLab",L"2024-03-30");
                        std::vector<OwnerPtr<IPick>>& picks = pickResults->GetAllPicks();
                        DBG_WARN_AND_RETURN_UNLESS(picks.at(0), false, L"picks.at(0) 为空",L"GDMPLab",L"2024-03-30");
                        gcmp::GraphicsNodeReferenceOwnerPtrVector& pickData = picks.at(0)->GetAllGraphicsNodeReferencesFw();
                        //过滤框选的辅助对象
                        IDocument *pDoc = GetDoc();
                        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
                        RemoveAuxiliaryElementHelper removeHelper(dynamic_cast<IDocument*>(pDoc));
                        OwnerPtrContainerUtil::RemoveItemsIf(pickData, removeHelper);
                        IPreHighlights::Get()->SetGraphicsNodeReferences(pickData);
                    }
                    else
                        IPreHighlights::Get()->Clear();
                }
            }
        }
    }
    else
    {
        if (IsPickVisible())
            isUpdatedView = UpdateCandidates(pCurrentView, pos);
    }

    //移动显示场景有：随鼠标移动的临时对象显示、捕捉显示、高亮选择（不会修改Elements）
    if (!isUpdatedView)
    {
        UpdateView();
    }
    return true;
}

bool GbmpPickActionBase::OnLButtonUp(IUiView* pCurrentView, const Vector3d& pos)
{
    m_auxElementId = ElementId::InvalidID;
    // 如果已经选中物体且未按住ctrl或shift键，则不允许框选
    if (((m_status & PS_GBMP_LBUTTON_DOWN) == 0) ||
        (!IsSelectionEmpty() && !IsKeyAndButtonPressed(VK_CONTROL) && !IsKeyAndButtonPressed(VK_SHIFT)) ||
        (IsDraggingAwaySelectedElementsEnabled(pCurrentView)))
    {
        m_status = PS_GBMP_LBUTTON_UP;
        ICanvas *pCanvas = pCurrentView->GetCanvas();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
        pCanvas->Refresh();
        return true;
    }
    m_status = PS_GBMP_LBUTTON_UP;
    IDocument *pDoc = GetDoc();

    if (m_rectangleSelectID.IsValid())
    {
        IPureGraphicsElement* pElement = quick_cast<IPureGraphicsElement>(pDoc->GetElement(m_rectangleSelectID));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"quick_cast<IPureGraphicsElement>(pDoc->GetElement(m_rectangleSelectID)) 返回空指针",L"GDMPLab",L"2024-03-30");
        IElementModelShape* pGraphicsElementShapeBehavior = pElement->GetElementModelShape();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pGraphicsElementShapeBehavior, L"pGraphicsElementShapeBehavior为空",L"GDMPLab",L"2024-03-30");
        const IGraphicsElementShape* pGRep = pGraphicsElementShapeBehavior->GetGraphicsElementShape();
        if (pGRep == nullptr || (pGRep && pGRep->GetChildrenCount() > 0))
        {
            gcmp::OwnerPtr<IGraphicsElementShape> pTempEmptyGrep(IGraphicsElementShape::Create(GraphicsRenderLayer::TransientObject));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pTempEmptyGrep, L"IGraphicsElementShape::Create创建失败",L"GDMPLab",L"2024-03-30");
            const IGraphicsStyleManager* pStyleManager = pDoc->GetGraphicsStyleManager();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pStyleManager, L"pDoc->GetGraphicsStyleManager() 返回空指针",L"GDMPLab",L"2024-03-30");
            pTempEmptyGrep->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE));
            pGraphicsElementShapeBehavior->SetGraphicsElementShape(TransferOwnership(pTempEmptyGrep));
        }
    }

    //时间统计
    // 实现框选
    Vector2d screenStart, screenPos;
    WorldToScreen(pCurrentView, m_worldStart, screenStart);
    WorldToScreen(pCurrentView, pos, screenPos);
    if ((screenPos - screenStart).Length() < gcmp::Constants::LENGTH_EPS)
    {
        ICanvas *pCanvas = pCurrentView->GetCanvas();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");
        pCanvas->Refresh();
        return true;
    }   

    bool isReversePick = false;
    OwnerPtr<IPickResult> pickResults = GetPickResults(pCurrentView, pos, isReversePick);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pickResults, L"pickResults为空",L"GDMPLab",L"2024-03-30");
    if (!pickResults->IsEmpty())
    {
        DBG_WARN_AND_RETURN_UNLESS(pickResults->GetSize()==1, false, L"框选选择集只可能是一个PickCandidate结果",L"GDMPLab",L"2024-03-30");
        std::vector<OwnerPtr<IPick>>& picks = pickResults->GetAllPicks();
        DBG_WARN_AND_RETURN_UNLESS(picks.at(0), false, L"picks.at(0) 为空",L"GDMPLab",L"2024-03-30");
        gcmp::GraphicsNodeReferenceOwnerPtrVector& pickData = picks.at(0)->GetAllGraphicsNodeReferencesFw();
        //过滤框选的辅助对象
        RemoveAuxiliaryElementHelper removeHelper(dynamic_cast<IDocument*>(pDoc));
        OwnerPtrContainerUtil::RemoveItemsIf(pickData, removeHelper);

        {
            GraphicsNodeReferenceOwnerPtrSet pickSets;
            pickSets.clear();

            IEditMode* pEditModeUE = IEditMode::GetTopActiveEditMode(pDoc);
            if (pEditModeUE)
            {
                for (auto iter = pickData.begin(); iter != pickData.end();++iter)
                {
                    if (IsAuxiliaryElement(pDoc,(*iter)->GetElementId()))
                        continue;

                    const IElement* pElement = pDoc->GetElement((*iter)->GetElementId());
                    if(!pEditModeUE->IsElementEditable(pElement))
                        continue;

                    OwnerPtrContainerUtil::AddItem(pickSets, **iter);
                }
            }
            else
            {
                OwnerPtrContainerUtil::AddItems(pickSets, pickData);
            }
            AddToSelectionGroup(pDoc, pickSets);

        }
    }

    OnSelectionChanged();

    if(JournalUtils::IsInReplay() && DEBUG_MODE(DisplayMousePositionInReplay))
    {
        DrawSelectRectangleInReplay(pCurrentView,pos,isReversePick);
    }

    //视图刷新时间
    UpdateView();
    return true;
}

bool GbmpPickActionBase::UpdateCandidates(IUiView* pCurrentView, const Vector3d& pos)
{
    int screenX, screenY;
    float depth;
    UiViewUtility::WorldPositionToScreenPosition(pCurrentView, pos, screenX, screenY, depth);

    const GraphicsNodeReferenceOwnerPtrVector& preHighlights = IPreHighlights::Get()->GetAllGraphicsNodeReferences();
    GraphicsNodeReferenceOwnerPtrVector oldPreHighlights;
    OwnerPtrContainerUtil::AddItems(oldPreHighlights, preHighlights);

    //根据拾取条件，更新全局的选择集
    GbmpPickActionUtil::UpdateCandidatesSingleton(pCurrentView, screenX, screenY, pos, m_opPickPostProcessEvent.get()
        , m_upPickFilter.get(), m_pickTarget.get(), m_isPickingHighlightOnlyGraphicsNodeAllowed,
        m_bSelectByFaceInteriorEnabled, m_pickPixelTolerance, m_isHoveringHighlight);

    const GraphicsNodeReferenceOwnerPtrVector& candidates = IPickCandidates::Get()->GetCurrentPick()->GetAllGraphicsNodeReferences();
    if (!candidates.empty())
    {
        //IPreHighlights::Get()->AddGraphicsNodeReferences(GetElementAssociatedCandidatesObjects(candidates.at(0)->GetElementId()));
    }

    const GraphicsNodeReferenceOwnerPtrVector& newPreHighlights = IPreHighlights::Get()->GetAllGraphicsNodeReferences();
    //只有当预高亮变换时，刷新视图，否则非常耗性能！
    if (!OwnerPtrContainerUtil::IsSameContentContainer(oldPreHighlights, newPreHighlights))
    {
        UpdateView();
        return true;
    }

    return false;
}

std::wstring GbmpPickActionBase::GetPromptMessage() const
{
    IDocument* pDocument = GetDoc();
    const GraphicsNodeReferenceOwnerPtrVector& curCandidate = IPickCandidates::Get()->GetCurrentPick()->GetAllGraphicsNodeReferences();
   
    if (!pDocument || curCandidate.empty())
    {
        if (DEBUG_MODE(GBMPDisplayElementTriangleNumber))
        {
            return ActionBase::GetPromptMessage() + DisplayElementTriangleNumberOnStatusBar();
        }
        else
            return ActionBase::GetPromptMessage();
    }

    const IElement* pElem = pDocument->GetElement(curCandidate.at(0)->GetElementId());
    if (!pElem)
        return ActionBase::GetPromptMessage();

    //TODO:暂时注掉，显示Pick对象信息输出到状态栏用于调试
    ////std::wstring msg = PickUtil::GetElementDescription(dynamic_cast<IDocument*>(pDocument), curCandidate.at(0)->GetElementId());
    std::wstring msg;
    const IConfigRecord* pInHouseModeConfigRecord = IPublishConfig::GetConfigRecord(PublishConfigRecordNames::InHouseMode);
    if (pInHouseModeConfigRecord && pInHouseModeConfigRecord->IsInternalIdentifyCodeValue())
    {
        if (!DEBUG_MODE(GBMPDontPrintCandidateOnStatusBar))
            msg += curCandidate.at(0)->GetDescriptionString();
    }

    // 显示所选对象的三角面片数量
    if (DEBUG_MODE(GBMPDisplayElementTriangleNumber))
        msg = msg + DisplayElementTriangleNumberOnStatusBar();

    return msg;
}


std::wstring gcmp::GbmpPickActionBase::DisplayElementTriangleNumberOnStatusBar() const
{
    std::wstring msg(L"");

    return msg;
}

bool gcmp::GbmpPickActionBase::IsDraggingAwaySelectedElementsEnabled(const IUiView * pCurrentView)
{
    if (pCurrentView && pCurrentView->IsDraggingAwaySelectedElementsEnabled() && IsKeyAndButtonPressed(VK_MENU))
    {
        return true;
    }
    return false;
}

void GbmpPickActionBase::WorldToScreen(const IUiView *pCurrentView, const Vector3d &world, Vector2d &screen) const
{
    int x = 0, y = 0;
    float depth = 0.0f;
    UiViewUtility::WorldPositionToScreenPosition(pCurrentView, world, x, y, depth);
    screen.Set(x, y);
}

void GbmpPickActionBase::ClearSelection(gcmp::IDocument* pDoc)
{
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
}

bool GbmpPickActionBase::IsSelectionEmpty()
{
    return ISelection::Get()->GetCount() <= 0;
}

bool GbmpPickActionBase::IsCanBeSelect(gcmp::IDocument* pDoc, const IGraphicsNodeReference& refAdd)
{
    IEditMode* pEditModeUE = IEditMode::GetTopActiveEditMode(pDoc);
    if (pEditModeUE)
    {
        const IElement* pElement = pDoc->GetElement(refAdd.GetElementId());
        if(!pEditModeUE->IsElementEditable(pElement))
            return false;
    }
    return true;
}

bool GbmpPickActionBase::IsPickVisible()
{
    if(IsKeyAndButtonPressed(VK_MBUTTON))
        return false;
    return true;
}

void GbmpPickActionBase::ActionCancelled()
{
    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"pUiDicMgr为空指针",L"GDMPLab",L"2024-03-30");
    IUiDocument* pUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDocViewMgr->GetCurrentUiDocument() 返回空指针",L"GDMPLab",L"2024-03-30");
    const IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pUiDoc->GetDbDocument() 返回空指针",L"GDMPLab",L"2024-03-30");

    if (m_rectangleSelectID.IsValid())
    {
        IPureGraphicsElement* pElement = quick_cast<IPureGraphicsElement>(pDoc->GetElement(m_rectangleSelectID));
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"quick_cast<IPureGraphicsElement>(pDoc->GetElement(m_rectangleSelectID)) 返回空指针",L"GDMPLab",L"2024-03-30");
        IElementModelShape* pGraphicsElementShapeBehavior = pElement->GetElementModelShape();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pGraphicsElementShapeBehavior, L"pGraphicsElementShapeBehavior为空",L"GDMPLab",L"2024-03-30");
        const IGraphicsElementShape* pGRep = pGraphicsElementShapeBehavior->GetGraphicsElementShape();
        if (pGRep == nullptr || (pGRep && pGRep->GetChildrenCount() > 0))
        {
            gcmp::OwnerPtr<IGraphicsElementShape> pTempEmptyGrep(IGraphicsElementShape::Create(GraphicsRenderLayer::TransientObject));
            DBG_WARN_AND_RETURN_VOID_UNLESS(pTempEmptyGrep, L"IGraphicsElementShape::Create创建失败",L"GDMPLab",L"2024-03-30");
            const IGraphicsStyleManager* pStyleManager = pDoc->GetGraphicsStyleManager();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleManager, L"pDoc->GetGraphicsStyleManager() 返回空指针",L"GDMPLab",L"2024-03-30");
            pTempEmptyGrep->SetGraphicsStyleId(pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE));
            pGraphicsElementShapeBehavior->SetGraphicsElementShape(TransferOwnership(pTempEmptyGrep));
        }
    }
    MarkFinishStatus(ActionFinishStatus::Cancelled);
}

bool GbmpPickActionBase::AddPickPostProcessEvent(gcmp::IPickEventHandler* pPickEvent)
{
    if (pPickEvent != nullptr)
    {
        return m_opPickPostProcessEvent->Add(pPickEvent);
    }
    return false;
}

gcmp::IPickEvent* GbmpPickActionBase::GetPickPostProcessEvent() const
{
    return const_cast<gcmp::IPickEvent*>(m_opPickPostProcessEvent.get());
}

void GbmpPickActionBase::SetPickPostProcessEvent(OwnerPtr<gcmp::IPickEvent> opPickPostProcessEvent)
{
    if (opPickPostProcessEvent != nullptr)
        m_opPickPostProcessEvent = TransferOwnership(opPickPostProcessEvent);
}

bool GbmpPickActionBase::AddRectPickPostProcessEvent(gcmp::IPickEventHandler* pPickEvent)
{
    if (pPickEvent != nullptr)
    {
        return m_opRectPickPostProcessEvent->Add(pPickEvent);
    }
    return false;
}

gcmp::IPickEvent* GbmpPickActionBase::GetRectPickPostProcessEvent() const
{
    return const_cast<gcmp::IPickEvent*>(m_opRectPickPostProcessEvent.get());
}

void GbmpPickActionBase::SetRectPickPostProcessEvent(OwnerPtr<gcmp::IPickEvent> opRectPickPostProcessEvent)
{
    if (opRectPickPostProcessEvent != nullptr)
        m_opRectPickPostProcessEvent = TransferOwnership(opRectPickPostProcessEvent);
}

void GbmpPickActionBase::SetPickTarget(OwnerPtr<gcmp::IPickTarget> pickTarget)
{
    if (pickTarget != nullptr)
        m_pickTarget = TransferOwnership(pickTarget);
}

void GbmpPickActionBase::SetPickFilter(OwnerPtr<gcmp::IPickFilter>  opPickFilter)
{
    if (opPickFilter != nullptr)
        m_upPickFilter = TransferOwnership(opPickFilter);
}

void GbmpPickActionBase::SetPickPixelTolerance(int tolerance)
{
    m_pickPixelTolerance = tolerance;
}

OwnerPtr<IPickResult> GbmpPickActionBase::GetPickResults(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos, bool& isReversePick) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCurrentView, L"pCurrentView为空",L"GDMPLab",L"2024-03-30");
    IDocument *pDoc = GetDoc();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    ICanvas *pCanvas = pCurrentView->GetCanvas();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCanvas, L"pCanvas为空",L"GDMPLab",L"2024-03-30");

    Vector2d screenStart, screenPos;
    WorldToScreen(pCurrentView, m_worldStart, screenStart);
    WorldToScreen(pCurrentView, pos, screenPos);
    if ((screenPos - screenStart).Length() < gcmp::Constants::LENGTH_EPS)
    {
        return nullptr;
    }
    isReversePick = screenStart.X() > screenPos.X() ? true : false;
    const ICamera* pCamera = pCanvas->GetCamera();
    DBG_WARN_AND_RETURN_UNLESS(pCamera, false, L"pCamera为空",L"GDMPLab",L"2024-03-30");

    Vector3d viewDir = pCamera->GetDirection(),
        upDir = pCamera->GetUpDirection(),
        uDir = viewDir.Cross(upDir);
    uDir.Normalize();

    Vector3d coordPos = (m_worldStart + pos) / 2;
    Coordinate3d coord(coordPos, Vector3d(uDir.X(), uDir.Y(), uDir.Z()), Vector3d(upDir.X(), upDir.Y(), upDir.Z()));
    if (JournalUtils::IsInReplay()) {
        JournalUtils::SetMousePoint(pos);
    }
    std::vector<const IGraphicsElementShape*> greps = pCurrentView->GetEditableGreps();
    OwnerPtr<ILine3d> ray = UiViewUtility::WorldPositionToWorldRay(pCurrentView, coordPos);
    ray->SetLimits(Intervald(ray->GetStartLimit() - 50000, ray->GetEndLimit() + 50000));

    OwnerPtr<IRectPickContext> pickContext = gcmp::IRectPickContext::Create();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pickContext, L"pickContext为空",L"GDMPLab",L"2024-03-30");
    std::vector<const IGraphicsElementShape*> apiGreps;
    FOR_EACH(item, greps)
    {
        apiGreps.emplace_back(const_cast<const gcmp::IGraphicsElementShape*>(item));
    }
    pickContext->SetDocument(pDoc);
    pickContext->SetViewerContext(pCurrentView->GetViewerContext()->Clone());
    pickContext->SetGraphicsElementShapes(apiGreps);
    pickContext->SetRay(ray.ReleaseOwnership());
    pickContext->SetRectangle(m_worldStart, pos, coord);
    pickContext->SetReversePick(isReversePick);
    //m_pickTarget->EnableDocReference();
    pickContext->SetPickTarget(TransferOwnership(m_pickTarget->Clone()));
    pickContext->SetAllowPickingHighlightOnlyGraphicsNode(IsPickingHighlightOnlyGraphicsNodeAllowed());
    //暂时保留，如果UI层全部替换为API事件形式以后，可以删除
    if (m_upPickFilter.get() != nullptr)
        pickContext->SetPickFilter(m_upPickFilter.get());
    if (m_opRectPickPostProcessEvent != nullptr)
        pickContext->SetPickPostProcessEvent(m_opRectPickPostProcessEvent.get());

    pickContext->SetSelectByFaceInteriorEnabled(m_bSelectByFaceInteriorEnabled);

    if (DEBUG_MODE(GBMPPickFaceInWireframeMode))
    {
        pickContext->SetSelectByFaceInteriorEnabled(true);
    }

    OwnerPtr<IPickResult> pickResults = gcmp::IPicker::PickByRectangle(pickContext.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pickResults, L"pickResults为空",L"GDMPLab",L"2024-03-30");

    return TransferOwnership(pickResults);
}

